/*
@(#)MenuController   2024-11-07
 
Copyright (c) 2011-2024 杭州湖畔网络技术有限公司 
保留所有权利 
本软件为杭州湖畔网络技术有限公司所有及包含机密信息，须遵守其相关许可证条款进行使用。
Copyright (c) 2011-2024 HUPUN Network Technology CO.,LTD.
All rights reserved.
This software is the confidential and proprietary information of HUPUN
Network Technology CO.,LTD("Confidential Information").  You shall not
disclose such Confidential Information and shall use it only in
accordance with the terms of the license agreement you entered into with HUPUN.
Website：http://www.hupun.com
*/
package org.obp.upms.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.obp.core.result.ApiResult;
import org.obp.data.utils.ObjectUtils;
import org.obp.upms.context.WorkUserHolder;
import org.obp.upms.domain.request.RoleMenuParam;
import org.obp.upms.domain.response.MenuTreeVO;
import org.obp.upms.model.WorkMenuDO;
import org.obp.upms.model.WorkRoleMenuDO;
import org.obp.upms.service.WorkMenuService;
import org.obp.upms.service.WorkRoleMenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author: Jackey 2024/11/7
 */
@RestController
@RequestMapping("/v1/work/menu")
@Api(tags = {"菜单接口"})
public class MenuController {

    @Autowired
    private WorkUserHolder workUserHolder;
    @Autowired
    private WorkMenuService workMenuService;
    @Autowired
    private WorkRoleMenuService workRoleMenuService;

    @ApiOperation("用户菜单列表")
    @GetMapping("/list")
    public ApiResult<List<MenuTreeVO>> menuList() {

        String userID = workUserHolder.getCurrentUserID();

        List<WorkMenuDO> menuDOs = workMenuService.getMenusByUserId(userID);
        List<MenuTreeVO> menuTreeVOS = ObjectUtils.copyList(menuDOs, MenuTreeVO.class, ((source, target) -> target.setPermit(true)));

        return ApiResult.ok(this.buildMenuTree(menuTreeVOS));
    }

    @ApiOperation("角色菜单列表")
    @GetMapping("/list/byRole")
    public ApiResult<List<MenuTreeVO>> menuListByRole(String roleId) {

        List<WorkMenuDO> menuDOs = workMenuService.lambdaQuery().orderByDesc(WorkMenuDO::getSortDesc).list();
        List<MenuTreeVO> menuTreeVOS = ObjectUtils.copyList(menuDOs, MenuTreeVO.class);

        List<WorkMenuDO> roleMenuDOs = workMenuService.getMenusByRoleId(roleId);
        if (!CollectionUtils.isEmpty(roleMenuDOs)) {
            List<String> menuIds = roleMenuDOs.stream().map(WorkMenuDO::getId).collect(Collectors.toList());
            menuTreeVOS.forEach(m -> m.setPermit(menuIds.contains(m.getId())));
        }

        return ApiResult.ok(this.buildMenuTree(menuTreeVOS));
    }

    @ApiOperation("菜单绑定角色")
    @PostMapping("/bind/role")
    public ApiResult<String> menuBindRole(@RequestBody RoleMenuParam param) {

        List<WorkRoleMenuDO> oldRelations = workRoleMenuService.lambdaQuery()
                .eq(WorkRoleMenuDO::getRoleId, param.getRoleId()).list();

        List<String> paramMenuIds = param.getMenuIds();
        List<String> oldMenuIds = oldRelations.stream()
                .map(WorkRoleMenuDO::getMenuId).collect(Collectors.toList());

        List<WorkRoleMenuDO> insertDOs = new ArrayList<>();
        for (String paramMenuId : paramMenuIds) {
            if (oldMenuIds.contains(paramMenuId)) continue;
            WorkRoleMenuDO workRoleMenu = new WorkRoleMenuDO();
            workRoleMenu.setRoleId(param.getRoleId());
            workRoleMenu.setMenuId(paramMenuId);
            insertDOs.add(workRoleMenu);
        }
        if (!CollectionUtils.isEmpty(insertDOs)) {
            workRoleMenuService.saveBatch(insertDOs);
        }

        List<String> deleteIds = new ArrayList<>();
        for (String oldMenuId : oldMenuIds) {
            if (paramMenuIds.contains(oldMenuId)) continue;
            deleteIds.add(oldMenuId);
        }
        if (!CollectionUtils.isEmpty(deleteIds)) {
            workRoleMenuService.remove(new QueryWrapper<WorkRoleMenuDO>().lambda()
                    .in(WorkRoleMenuDO::getMenuId, deleteIds)
                    .eq(WorkRoleMenuDO::getRoleId, param.getRoleId()));
        }

        return ApiResult.ok();
    }

    @ApiOperation("菜单解绑角色")
    @PostMapping("/unbind/role")
    public ApiResult<String> menuUnbindRole(@RequestBody RoleMenuParam param) {
        for (String menuId : param.getMenuIds()) {
            String roleId = param.getRoleId();
            workRoleMenuService.remove(new QueryWrapper<WorkRoleMenuDO>().lambda()
                    .eq(WorkRoleMenuDO::getMenuId, menuId)
                    .eq(WorkRoleMenuDO::getRoleId, roleId));
        }
        return ApiResult.ok();
    }

    @ApiOperation("全量菜单列表")
    @GetMapping("/list/all")
    public ApiResult<List<MenuTreeVO>> menuListAll() {

        List<WorkMenuDO> menuDOs = workMenuService.lambdaQuery().orderByDesc(WorkMenuDO::getSortDesc).list();
        List<MenuTreeVO> menuTreeVOS = ObjectUtils.copyList(menuDOs, MenuTreeVO.class);

        return ApiResult.ok(this.buildMenuTree(menuTreeVOS));
    }

    @ApiOperation("菜单新增功能")
    @PostMapping("/insert")
    public ApiResult<WorkMenuDO> menuInsert(@Validated @RequestBody WorkMenuDO menu) {
        workMenuService.save(menu);
        return ApiResult.ok(menu);
    }

    @ApiOperation("菜单更新功能")
    @PostMapping("/update")
    public ApiResult<String> menuUpdate(@Validated @RequestBody WorkMenuDO menu) {
        workMenuService.updateById(menu);
        return ApiResult.ok();
    }

    @ApiOperation("菜单删除功能")
    @GetMapping("/delete")
    public ApiResult<String> menuDelete(@RequestParam String id) {
        workMenuService.deleteById(id);
        return ApiResult.ok();
    }

    private List<MenuTreeVO> buildMenuTree(List<MenuTreeVO> menuItems) {
        List<MenuTreeVO> rootItems = new ArrayList<>();
        for (MenuTreeVO menuItem : menuItems) {
            if (Objects.equals(menuItem.getParentId(), WorkMenuDO.DEFAULT_PARENT_ID)) {
                rootItems.add(menuItem);
            }
        }
        for (MenuTreeVO rootItem : rootItems) {
            addChildren(rootItem, menuItems);
        }
        return rootItems;
    }

    private void addChildren(MenuTreeVO parent, List<MenuTreeVO> menuItems) {
        for (MenuTreeVO menuItem : menuItems) {
            if (Objects.equals(menuItem.getParentId(), parent.getId())) {
                parent.getChildren().add(menuItem);
                addChildren(menuItem, menuItems);
            }
        }
    }

}